﻿/**

 * Copyright (c) 2015-2016, FastDev 刘强 (fastdev@163.com) & Quincy.

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */


using OF.DistributeService.Core.Attribute;
using OF.DistributeService.Core.Client;
using OF.DistributeService.Core.Client.Entity;
using OF.DistributeService.Core.Common;
using OF.DistributeService.Core.Entity;
using OF.Notify.DataHost;
using OF.Notify.DataHost.Cluster;
using OF.Notify.DataHost.Cluster.Entity;
using OF.Notify.Entity;
using OF.Notify.Master;
using OF.Notify.Test.Entity;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OF.Notify.Channel
{
    public class NotifyServiceProvider : INotifyServiceProvider
    {
        internal static ConcurrentDictionary<string, INotifyService> dict = new ConcurrentDictionary<string, INotifyService>();
        internal static Type currentType = typeof(NotifyServiceProvider);
        internal static EmitHelper emitHelper = new EmitHelper();
        internal static DataNode dataNodeService = null;
        
        public void InitCurrentDataNode(DataNode dataNodeService)
        {
            NotifyServiceProvider.dataNodeService = dataNodeService;
        }

        public INotifyService GetNotifyService(DataNodeProxy proxy)
        {
            if (NotifyServiceProvider.dataNodeService != null
                && NotifyServiceProvider.dataNodeService.IsSameNode(proxy))
            {
                return NotifyServiceProvider.dataNodeService;
            }
            else
            {
                return GetNotifyService(proxy.GetUrl());
            }
        }

        public INotifyService GetNotifyService(string notifyServiceUrl)
        {
            INotifyService notifyService = null;
            if (!dict.TryGetValue(notifyServiceUrl, out notifyService))
            { 
                notifyService = emitHelper.GetAPIProxy<INotifyService>(null, new NotifyApiCallProxy(notifyServiceUrl));
                dict.AddOrUpdate(notifyServiceUrl, notifyService, (k, v) => notifyService);
            }
            return notifyService;
        }

        public void VisitAllNodes(ClusterMaster clusterMaster, byte topicEnum, AllNodesRuntimeData result)
        {
            if (WebApiApplicationBase.dataNodeService.masterNode != null)
            {
                var nodes = WebApiApplicationBase.dataNodeService.masterNode.dataNodeProxyDict.Values.ToList();
                foreach (var node in nodes)
                {
                    var data = node.GetRuntimeData(new GetRuntimeDataRequest { topicEnum = topicEnum });
                    if (data != null)
                    {
                        result.NodeRuntimeDataList.Add(data);
                    }
                }
                result.NodeCount = nodes.Count;
                result.OnlineNodeCount = clusterMaster.dataNodeProxyDict.Count;
                result.OnLineNodeIds = clusterMaster.dataNodeProxyDict.Keys.ToList();
            }
        }
    }

    public class NotifyApiCallProxy : ICommonApiCallProxy
    {
        internal static ApiContentFormat DefaultApiContentFormat = ApiContentFormat.JSON;//ApiContentFormat.MSGPack;

        internal string serviceUrl = null;
        public NotifyApiCallProxy(string serviceUrl)
        {
            this.serviceUrl = serviceUrl;
        }

        public void InvokeVoid(CommonApiCallContext callContext, ClientToAppServiceMeta meta)
        {
            callContext.IsVoidType = true;
            Invoke<object>(callContext, meta);
        }

        public T Invoke<T>(CommonApiCallContext callContext, ClientToAppServiceMeta meta)
        {
            string methodUrl = null;
            try
            {
                methodUrl = this.serviceUrl + "/" + callContext.MethodName;
                T result = WebApiUtil.Post<T>(methodUrl, callContext.Params, DefaultApiContentFormat);
                return result;
            }
            catch (Exception ex)
            {
                Util.LogException("call url:" + methodUrl, ex);
                throw;
            }
        }
    }
}
